﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using Microsoft.Phone.Controls;

namespace KouDai.Phone.Controls
{
    public class ScrollViewerMonitor
    {
        private static GestureListener gestureListener = null;

        public static DependencyProperty AtTopCommandProperty = 
            DependencyProperty.RegisterAttached("AtTopCommand", typeof(ICommand), typeof(ScrollViewerMonitor),
            new PropertyMetadata(new PropertyChangedCallback(OnAtTopCommandChanged)));

        public static DependencyProperty ShowReleaseCommandProperty = 
            DependencyProperty.RegisterAttached( "ShowReleaseCommand", typeof(ICommand), typeof(ScrollViewerMonitor),new PropertyMetadata(null));

        public static ICommand GetShowReleaseCommand(DependencyObject obj)
        {
            return (ICommand)obj.GetValue(ScrollViewerMonitor.ShowReleaseCommandProperty);
        }

        public static ICommand GetAtTopCommand(DependencyObject obj)
        {
            return (ICommand)obj.GetValue(ScrollViewerMonitor.AtTopCommandProperty);
        }

        public static void OnAtTopCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            FrameworkElement frameworkElement = (FrameworkElement)d;
            if (frameworkElement != null)
            {
                frameworkElement.Loaded -= element_Loaded;
                frameworkElement.Loaded += element_Loaded;
            }
        }

        private static void element_Loaded(object sender, RoutedEventArgs e)
        {
            FrameworkElement element = (FrameworkElement)sender;
            element.Loaded -= element_Loaded;

            ScrollViewer scrollViewer = ScrollViewerMonitor.FindChildOfType<ScrollViewer>(element);
            if (scrollViewer == null)
            {
                throw new InvalidOperationException("ScrollViewer not found.");
            }
            gestureListener = GestureService.GetGestureListener(element);
            gestureListener.DragDelta += gestureListener_DragDelta;
            gestureListener.DragCompleted += gestureListener_DragCompleted;
        }

        static void gestureListener_DragCompleted(object sender, DragCompletedGestureEventArgs e)
        {
            gestureListener.DragCompleted -= gestureListener_DragCompleted;

            FrameworkElement element = (FrameworkElement)sender;
            ScrollViewer scrollViewer = ScrollViewerMonitor.FindChildOfType<ScrollViewer>(element);
            if (scrollViewer == null)
            {
                throw new InvalidOperationException("ScrollViewer not found.");
            }
            //Debug.WriteLine("verticalcahnge-->" + e.VerticalChange.ToString());
            if (e.VerticalChange > 100 && scrollViewer.VerticalOffset < 0.1)
            {
                ICommand atTopCommand = ScrollViewerMonitor.GetAtTopCommand(element);
                if (atTopCommand != null)
                {
                    atTopCommand.Execute(null);
                }
            }
        }

        static void gestureListener_DragDelta(object sender, DragDeltaGestureEventArgs e)
        {
            gestureListener.DragDelta -= gestureListener_DragDelta;

            FrameworkElement element = (FrameworkElement)sender;
            ScrollViewer scrollViewer = ScrollViewerMonitor.FindChildOfType<ScrollViewer>(element);
            if (scrollViewer == null)
            {
                throw new InvalidOperationException("ScrollViewer not found.");
            }
            if (e.VerticalChange > 100 && scrollViewer.VerticalOffset < 0.1)
            {
                ICommand showReleaseCommand = ScrollViewerMonitor.GetShowReleaseCommand(element);
                if (showReleaseCommand != null)
                {
                    showReleaseCommand.Execute(null);
                }
            }
        }

 
        private static T FindChildOfType<T>(DependencyObject root) where T : class
        {
            Queue<DependencyObject> queue = new Queue<DependencyObject>();
            queue.Enqueue(root);
            while (queue.Count > 0)
            {
                DependencyObject dependencyObject = queue.Dequeue();
                int num = VisualTreeHelper.GetChildrenCount(dependencyObject) - 1;
                while (0 <= num)
                {
                    DependencyObject child = VisualTreeHelper.GetChild(dependencyObject, num);
                    T t = child as T;
                    if (t != null)
                    {
                        return t;
                    }
                    queue.Enqueue(child);
                    num--;
                }
            }
            return default(T);
        }
    }
}
